package com.itrus.contract.extension.shardinsphere;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.infra.datanode.DataNode;
import org.apache.shardingsphere.sharding.rule.TableRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Component
public class ShardingActualDataNodeManager {


//    @Autowired
//    private ShardingTableNameManager shardingTableNameManager;
//    @Autowired
//    private ContractDataSource contractDataSource;
    @Autowired
    private DataSource datasource;
//    @Resource
//    private DdlTableManager ddlTableManager;
    @Autowired
    private ShardingDateManager shardingDateManager;

//    @Autowired
//    private RedisUtil redisUtil;

//    @Resource
//    private ContractMapper contractMapper;

    public void startedCheckShardingTable(){
//        if (TableRulesEnum.NORMAL.equals(shardingTableNameManager.getTableRules())){
//            log.info("配置不进行分表处理，不需要检查分表");
//            return;
//        }
        try {
            createCurrentNextShardingTable();
            log.info("检查当前及下个分表完成");
        } catch (Exception e){
            log.error("分表检查异常",e);
        }

        try {
            refreshShardingActualDataNodes();
            log.info("刷新分表节点完成");
        } catch (Exception e){
            log.error("刷新分表节点异常",e);
        }
    }

    public void checkUpgradeShardingTable(){
        StopWatch watch = new StopWatch("检查所有升级分表");
        try {
            watch.start("创建升级分表");
            createUpgradeShardingTable();
            watch.stop();
        } catch (Exception e){
            log.error("分表检查异常",e);
        }

        try {
            watch.start("更新分表配置");
            refreshShardingActualDataNodes();
            watch.stop();
        } catch (Exception e){
            log.error("刷新分表节点异常",e);
        }
        log.info(watch.prettyPrint());
    }


    /**
     * 创建需要升级的分表
     */
    private void createUpgradeShardingTable(){

//        Integer maxDate = Integer.parseInt(LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE));
//        Integer minDate = Integer.parseInt(LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE));
//        Map<String, Object> map = contractMapper.queryMaxMinShardingDate();
//        if (Objects.nonNull(map)){
//            maxDate = Integer.parseInt(map.getOrDefault("MAXDATE",LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)).toString());
//            minDate = Integer.parseInt(map.getOrDefault("MINDATE",LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)).toString());
//        }
//        TableRulesEnum rulesEnum = shardingTableNameManager.getUpgradeTableRule();
//        List<String> postfixList = ShardingDateValueUtil.calcPostfixList(minDate, maxDate, rulesEnum);
////        log.info("初始化全量升级分表,查询合同表最小日期:[{}]，最大日期:[{}]，分表规则:[{}]，分表后缀:[{}]",minDate,maxDate, rulesEnum, JSONObject.toJSONString(postfixList));
//
//        Map<ShardingTableEnum,List<String>>  expectTableMap = new ConcurrentHashMap<>();
//        for (ShardingTableEnum value : ShardingTableEnum.values()) {
//            List<String> list = new ArrayList<>();
//            for (String postfix : postfixList) {
//                list.add(value.getTableName().concat("_").concat(postfix));
//            }
//            expectTableMap.put(value, list);
//        }
//
//        Map<String, DruidDataSource> datasourceMap = contractDataSource.getDatasource();
//
//        Map<String, Map<ShardingTableEnum, List<String>>> tableNameMap = shardingTableNameManager.queryShardingTablesList(datasourceMap);
//        tableNameMap.forEach((k,v)->{
//            if (Objects.isNull(v) || CollectionUtils.isEmpty(v.keySet())){ //没有创建
//                expectTableMap.forEach((ek,ev)->{
//                    for (String tableName : ev) {
//                        ddlTableManager.execCreateTable(datasourceMap.get(k), shardingTableNameManager.getDatabaseType(),ek, tableName);
//                    }
//                });
//            } else {//已创建
//                expectTableMap.forEach((ek,ev)->{
//                    for (String tableName : ev) {
//                        if (!CollectionUtils.emptyIfNull(v.get(ek)).contains(tableName)){
//                            ddlTableManager.execCreateTable(datasourceMap.get(k), shardingTableNameManager.getDatabaseType(),ek, tableName);
//                        }
//                    }
//                });
//            }
//        });
        log.info("初始化分表完成");
    }


    /**
     * 创建当前及下个分表
     */
    private void createCurrentNextShardingTable(){

//        Map<String, DruidDataSource> datasourceMap = contractDataSource.getDatasource();
//
//        Map<String, Map<ShardingTableEnum, List<String>>> tableNameMap = shardingTableNameManager.queryShardingTablesList(datasourceMap);
//
//        Map<ShardingTableEnum, String> currentMap = shardingTableNameManager.getCurrentTableNameMap(LocalDate.now());
//        Map<ShardingTableEnum, String> nextMap = shardingTableNameManager.getNextTableNameMap(LocalDate.now());
//
//        AtomicBoolean isCreate = new AtomicBoolean(false);
//
//        tableNameMap.forEach((k,v)->{
//            if (Objects.isNull(v) || CollectionUtils.isEmpty(v.keySet())){ //没有创建
//                currentMap.forEach((a,b)->{
//                    log.info("dsName:[{}],shardingTable:[{}],当前分表[{}]不存在,进行创建",k,a,b);
//                    ddlTableManager.execCreateTable(datasourceMap.get(k), shardingTableNameManager.getDatabaseType(),a, b);
//                    isCreate.set(true);
//                });
//
//                nextMap.forEach((a,b)->{
//                    log.info("dsName:[{}],shardingTable:[{}],下个分表[{}]不存在,进行创建",k,a,b);
//                    ddlTableManager.execCreateTable(datasourceMap.get(k), shardingTableNameManager.getDatabaseType(), a, b);
//                    isCreate.set(true);
//                });
//            } else {//已创建
//                currentMap.forEach((a,b)->{
//                    if (!CollectionUtils.emptyIfNull(v.get(a)).contains(b)){ //不存在
//                        log.info("dsName:[{}],shardingTable:[{}],当前分表[{}]不存在,进行创建",k,a,b);
//                        ddlTableManager.execCreateTable(datasourceMap.get(k), shardingTableNameManager.getDatabaseType(), a, b);
//                        isCreate.set(true);
//                    }
//                });
//
//                nextMap.forEach((a,b)->{
//                    if (!CollectionUtils.emptyIfNull(v.get(a)).contains(b)){ //不存在
//                        log.info("dsName:[{}],shardingTable:[{}],下个分表[{}]不存在,进行创建",k,a,b);
//                        ddlTableManager.execCreateTable(datasourceMap.get(k), shardingTableNameManager.getDatabaseType(), a, b);
//                        isCreate.set(true);
//                    }
//                });
//            }
//        });
//
//        if (isCreate.get()){
//            log.info("补创建新的表，需要重新查询所有分表");
//            tableNameMap = shardingTableNameManager.queryShardingTablesList(datasourceMap);
//        }
//
//        shardingDateManager.queryShardingDateRange(tableNameMap);

    }



    public void refreshShardingActualDataNodes() throws NoSuchFieldException, IllegalAccessException {

//        if (TableRulesEnum.NORMAL.equals(shardingTableNameManager.getTableRules())){
//            log.info("配置不进行分表处理，不需要更新表节点数据");
//            return;
//        }

//        ShardingDataSource shardingDataSource = (ShardingDataSource) datasource;
//
//        ShardingRuntimeContext context = shardingDataSource.getRuntimeContext();
//
//        ShardingRule shardingRule = context.getRule();
//
//        Collection<TableRule> ruleCollection = shardingRule.getTableRules();
//
//        Map<String, Map<ShardingTableEnum, List<String>>> shardingTableMap = shardingTableNameManager.queryShardingTablesList(contractDataSource.getDatasource());
////
//        List<String> tableNameList = Arrays.stream(ShardingTableEnum.values()).map(o->o.getTableName()).collect(Collectors.toList());
////        //存在配置进行更新
//        for (TableRule tableRule : ruleCollection) {
//            String logicTable = tableRule.getLogicTable();
//            for (String actualDatasourceName : tableRule.getActualDatasourceNames()) {
//                List<DataNode> newDataNodes = new ArrayList<>();
//                //实际数据库 已有分表
//                Map<ShardingTableEnum, List<String>> shardingTableEnumListMap = shardingTableMap.get(actualDatasourceName);
//                if (ObjectUtils.isNotEmpty(shardingTableEnumListMap) && tableNameList.contains(logicTable)){
//                    ShardingTableEnum tableEnum = ShardingTableEnum.findByTableName(logicTable);
//                    List<String> tableList = shardingTableEnumListMap.get(tableEnum);
//                    for (String t : tableList) {
//                        if (logicTable.equalsIgnoreCase(t)){
//                            continue;
//                        }
//                        newDataNodes.add(new DataNode(actualDatasourceName, t));
//                    }
//
//                    dynamicRefreshDatasource(actualDatasourceName, tableRule, newDataNodes);
//                }
//            }
//        }


    }


    /**
     * 动态刷新数据源
     */
    private void dynamicRefreshDatasource(String dataSourceName, TableRule tableRule, List<DataNode> newDataNodes)
            throws NoSuchFieldException, IllegalAccessException {
        Set<String> actualTables = Sets.newHashSet();
        Map<DataNode, Integer> dataNodeIndexMap = Maps.newHashMap();
        AtomicInteger index = new AtomicInteger(0);
        newDataNodes.forEach(dataNode -> {
            actualTables.add(dataNode.getTableName());
            if (index.intValue() == 0) {
                dataNodeIndexMap.put(dataNode, 0);
            } else {
                dataNodeIndexMap.put(dataNode, index.intValue());
            }
            index.incrementAndGet();
        });
        // 动态刷新：actualDataNodesField
        Field actualDataNodesField = TableRule.class.getDeclaredField("actualDataNodes");
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(actualDataNodesField, actualDataNodesField.getModifiers() & ~Modifier.FINAL);
        actualDataNodesField.setAccessible(true);
        actualDataNodesField.set(tableRule, newDataNodes);
        // 动态刷新：actualTablesField
        Field actualTablesField = TableRule.class.getDeclaredField("actualTables");
        actualTablesField.setAccessible(true);
        actualTablesField.set(tableRule, actualTables);
        // 动态刷新：dataNodeIndexMapField
        Field dataNodeIndexMapField = TableRule.class.getDeclaredField("dataNodeIndexMap");
        dataNodeIndexMapField.setAccessible(true);
        dataNodeIndexMapField.set(tableRule, dataNodeIndexMap);

        // 动态刷新：datasourceToTablesMapField
        Map<String, Collection<String>> datasourceToTablesMap = Maps.newHashMap();
        datasourceToTablesMap.put(dataSourceName, actualTables);
        Field datasourceToTablesMapField = TableRule.class.getDeclaredField("datasourceToTablesMap");
        datasourceToTablesMapField.setAccessible(true);
        datasourceToTablesMapField.set(tableRule, datasourceToTablesMap);
    }


}
